package com.css.common.core.utils;


import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.css.common.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.TreeMap;

/**
 * @description: 加签/验签工具类
 * @Title: SignatureUtil
 * @Author xlw
 * @Package com.invoice.tcc.util
 * @Date 2024/11/26 18:43
 */
@Slf4j
public class SignatureUtil {


    /**
     * 排序参数
     *
     * @param json JSON 格式
     * @return {@link String }
     */
    public static String sortParams(String json) {
        Assert.notBlank(json, () -> new ServiceException("json不能为空"));
        JSONConfig config = new JSONConfig();
        config.setIgnoreNullValue(true);
        config.setDateFormat("yyyy-MM-dd HH:mm:dd");
        JSONObject obj = JSONUtil.parseObj(json, config);
        TreeMap<String, Object> treeMap = new TreeMap<>(String::compareTo);
        treeMap.putAll(obj);
        StringJoiner sj = new StringJoiner("&");
        treeMap.entrySet().stream().forEach(entry -> {
            sj.add(entry.getKey() + "=" + entry.getValue());
        });
        return sj.toString();
    }

    /**
     * 加签
     *
     * @param appid     appid
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @param appkey    appkey
     * @param body      请求体
     * @return {@link String }
     */
    public static String authorization(String appid, String timestamp, String nonce, String appkey, String body) {
        String localSignatureStr = signature(appid, timestamp, nonce, appkey, body);
        return "OPEN-BODY-SIG AppId=" + "\"" + appid + "\"" + ", Timestamp=" + "\"" + timestamp + "\"" + ", Nonce="
                + "\"" + nonce + "\"" + ", Signature=" + "\"" + localSignatureStr + "\"";
    }

    /**
     * 获取授权
     *
     * @param appid     appid
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @param signature 签名
     * @return {@link String }
     */
    public static String getAuthorization(String appid, String timestamp, String nonce, String signature) {
        return "OPEN-BODY-SIG AppId=" + "\"" + appid + "\"" + ", Timestamp=" + "\"" + timestamp + "\"" + ", Nonce="
                + "\"" + nonce + "\"" + ", Signature=" + "\"" + signature + "\"";
    }

    /**
     * 签名
     *
     * @param appid     appid
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @param appkey    appkey
     * @param body      请求体
     * @return {@link String }
     */
    public static String signature(String appid, String timestamp, String nonce, String appkey, String body) {
        try {
            byte[] data = body.getBytes("utf-8");
            InputStream is = new ByteArrayInputStream(data);
            String testSH = DigestUtils.sha256Hex(is);
            String s1 = appid + timestamp + nonce + testSH;
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(appkey.getBytes("utf-8"), "HmacSHA256"));
            byte[] localSignature = mac.doFinal(s1.getBytes("utf-8"));
            String signatureStr = Base64.encodeBase64String(localSignature);
            return signatureStr;
        } catch (Exception e) {
            log.error("加签失败", e);
        }
        return null;
    }

    /**
     * 验证
     *
     * @param appkey        appkey
     * @param body          请求体
     * @param authorization 认证头
     * @return boolean
     */
    public static boolean verify(String appkey, String body, String authorization) {
        String appid = "";
        String timestamp = "";
        String nonce = "";
        String signature = "";
        String authorizationStr = authorization.replaceAll("OPEN-BODY-SIG", "").replaceAll(" ", "").replaceAll("\"", "");
        String[] authArr = authorizationStr.split(",");
        for (String str : authArr) {
            if (str.startsWith("AppId=")) {
                appid = str.replaceFirst("AppId=", "");
            } else if (str.startsWith("Timestamp=")) {
                timestamp = str.replaceFirst("Timestamp=", "");
            } else if (str.startsWith("Nonce=")) {
                nonce = str.replaceFirst("Nonce=", "");
            } else if (str.startsWith("Signature=")) {
                signature = str.replaceFirst("Signature=", "");
            }
        }
        //加签
        try {
            byte[] data = body.getBytes("utf-8");
            InputStream is = new ByteArrayInputStream(data);
            String testSH = DigestUtils.sha256Hex(is);
            String s1 = appid + timestamp + nonce + testSH;
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(appkey.getBytes("utf-8"), "HmacSHA256"));
            byte[] localSignature = mac.doFinal(s1.getBytes("utf-8"));
            String localSignatureStr = Base64.encodeBase64String(localSignature);
            //验签
            if (Objects.equals(signature, localSignatureStr)) {
                return true;
            }
        } catch (Exception e) {
            log.error("验签失败", e);
        }
        return false;
    }

    /**
     * 验证
     *
     * @param appid     appid
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @param appkey    appkey
     * @param signature 签名
     * @param body      身体
     * @return boolean
     */
    public static boolean verify(String appid, String timestamp, String nonce, String appkey, String signature, String body) {
        //加签
        try {
            byte[] data = body.getBytes("utf-8");
            InputStream is = new ByteArrayInputStream(data);
            String testSH = DigestUtils.sha256Hex(is);
            String s1 = appid + timestamp + nonce + testSH;
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(appkey.getBytes("utf-8"), "HmacSHA256"));
            byte[] localSignature = mac.doFinal(s1.getBytes("utf-8"));
            String localSignatureStr = Base64.encodeBase64String(localSignature);
            //验签
            if (Objects.equals(signature, localSignatureStr)) {
                return true;
            }
        } catch (Exception e) {
            log.error("验签失败", e);
        }
        return false;
    }

    public static void main(String[] args) {

        String body = "ddbh=3AD7250120105613404520181126&ddcjrq=2025-01-20&sbyy=处理成功&ywlsh=1881173693061791746&zfjg=1";
        String appid = "a6a65c412cbb4d20ba15075ff7e2a81f";
        String appkey = "ff91c362c8ea4687a3003cce5030ed95";
        String timestamp = "1732792819973";
        String nonce = "sfOmbXeV";
        String signature = signature(appid, timestamp, nonce, appkey, body);
        System.out.println(signature);
        String authorization = SignatureUtil.getAuthorization(appid, timestamp, nonce, signature);
        System.out.println(authorization);
        System.out.println(SignatureUtil.verify(appkey, body, authorization));
    }
}
